/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.zkex.list.group;

import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.vos.datalist.ListGroupVo;
import cn.easyplatform.messages.vos.datalist.ListHeaderVo;
import cn.easyplatform.messages.vos.datalist.ListVo;
import cn.easyplatform.type.ListRowVo;
import cn.easyplatform.web.task.zkex.ListSupport;
import cn.easyplatform.web.task.support.CellCreater;
import cn.easyplatform.web.task.support.ExpressionEngine;
import cn.easyplatform.web.task.support.SupportFactory;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zul.Label;
import org.zkoss.zul.Row;
import org.zkoss.zul.Rows;

import java.util.HashMap;
import java.util.Map;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class ReportGroup extends Group {

    public static ReportGroup cast(ListSupport support, ExpressionEngine expressionEngine, ListGroupVo group,
                                   ListVo listVo) {
        ReportGroup rg = createGroup(support, expressionEngine, group, listVo, null, 0);
        if (rg.child != null)
            rg.maxLevel = ((ReportGroup) rg.child).maxLevel;
        return rg;
    }

    private static ReportGroup createGroup(ListSupport support, ExpressionEngine expressionEngine, ListGroupVo g,
                                           ListVo listVo, Group parent, int level) {
        ReportGroup group = new ReportGroup(support, expressionEngine, listVo, g.getFields());
        group.level = level + 1;
        group.name = g.getName();
        group.title = g.getTitle();
        group.style = g.getStyle();
        if (group.fieldIndexs.length == 0)
            group.maxLevel = 0;
        else
            group.maxLevel = group.level;
        if (parent != null) {
            parent.addGroup(group);
            group.rootNode = parent.getRoot();
            ((ReportGroup) parent).maxLevel = group.maxLevel;
        } else
            group.rootNode = new Rows();
        if (g.getChild() != null)
            createGroup(support, expressionEngine, g.getChild(), listVo, group, group.level);
        return group;
    }

    private ExpressionEngine expressionEngine;

    private int maxLevel;

    private String rowStyle;

    public ReportGroup(ListSupport support, ExpressionEngine expressionEngine, ListVo listVo, String[] fields) {
        super(support, listVo, fields);
        this.rowStyle = listVo.getRowStyle();
        this.expressionEngine = expressionEngine;
    }

    @Override
    public <T extends Component> T createGroup(ResultHelper rh,
                                               Map<String, Object> evalMap,
                                               Map<String, Component> managedComponents, int showLevel) {
        if (fieldIndexs.length == 0 || showLevel == 0) {// 清单
            createRow(rh.item(), evalMap, managedComponents);
        } else {
            Object[] ov = new Object[fieldIndexs.length];
            for (int i = 0; i < fieldIndexs.length; i++)
                ov[i] = rh.item().getData()[fieldIndexs[i]];
            boolean needGroup = false;
            if (oldValue != null && !Lang.equals(ov, oldValue))
                needGroup = true;
            Row row = null;
            if (child != null)
                child.save();
            if (needGroup) {
                row = createGroup(showLevel);
                if (showLevel == level) {
                    if (parent != null) {
                        Object[] vo = new Object[parent.fieldIndexs.length];
                        for (int i = 0; i < parent.fieldIndexs.length; i++)
                            vo[i] = rh.item().getData()[parent.fieldIndexs[i]];
                        if (parent.oldValue != null
                                && !Lang.equals(vo, parent.oldValue)) {
                            reIndex(true);
                        }
                    }
                } else if (child != null)
                    child.reset();
            }
            if (totalValues != null)
                for (TotalValue t : totalValues)
                    t.caculate(rh.item().getData()[support.getEntity().isShowRowNumbers() ? t.getIndex() - 1 : t.getIndex()].toString());
            if (child != null)
                child.createGroup(rh, evalMap, managedComponents, showLevel);
            oldValue = ov;
            if (row != null) {
                row.setParent(rootNode);
                if (!Strings.isBlank(style))
                    row.setStyle(style);
                else if (!Strings.isBlank(rowStyle))
                    row.setStyle(rowStyle);
            }
            if (parent == null) {// 顶层
                if (maxLevel < showLevel)
                    createRow(rh.item(), evalMap, managedComponents);
                else {
                    if (totalValues != null) {
                        Object[] data = rh.item().getData();
                        for (int i = 0; i < headers.size(); i++) {
                            ListHeaderVo hv = headers.get(i);
                            if (hv.isTotal() && data[support.getEntity().isShowRowNumbers() ? i - 1 : i] != null)
                                hv.caculate(data[support.getEntity().isShowRowNumbers() ? i - 1 : i].toString());
                        }
                    }
                }
                if (!rh.hasNext())
                    fillEnd(showLevel);
            }
        }
        return null;
    }

    private void fillEnd(int showLevel) {
        if (child != null)
            ((ReportGroup) child).fillEnd(showLevel);
        Row row = createGroup(showLevel);
        if (row != null) {
            row.setParent(rootNode);
            row.setStyle(style);
        }
    }

    private Row createGroup(int showLevel) {
        if (level > showLevel)
            return null;
        Map<String, Object> evalMap = null;
        Map<String, Component> managedComponents = null;
        if (groupEngine != null) {
            evalMap = new HashMap<String, Object>();
            evalMap.put("GROUP_NAME", this.name);
            managedComponents = new HashMap<String, Component>();
        }
        Row row = new Row();
        int i = 0;
        if (support.getEntity().isShowRowNumbers()) {
            i++;
            if (evalMap != null) {
                evalMap.put("LIST_INDEX", count);
                managedComponents.put("LIST_INDEX", row.getFirstChild());
            }
            if (showLevel <= maxLevel) {
                if (showLevel == level) {
                    setIndex(false);
                    row.appendChild(new Label("" + index));
                } else {
                    row.appendChild(new Label(Labels.getLabel(
                            "datalist.row.count", new Object[]{count == 0 ? 1
                                    : count})));
                    count = 0;
                }
            } else {
                row.appendChild(new Label(Labels.getLabel("datalist.row.count",
                        new Object[]{count})));
                count = 0;
                reIndex(false);
            }
        }
        for (; i < headers.size(); i++) {
            ListHeaderVo hv = headers.get(i);
            TotalValue tt = null;
            if (totalValues != null) {
                for (TotalValue gv : totalValues) {
                    if (gv.getIndex() == i) {
                        tt = gv;
                        break;
                    }
                }
            }
            Label label = new Label();
            if (tt != null) {
                label.setValue((hv.getGroupName() == null ? "" : hv
                        .getGroupName()) + tt.getValue(hv.getFormat()));
                if (evalMap != null) {
                    evalMap.put("SYS_COUNT", tt.getCount());
                    evalMap.put("SYS_TOTAL", tt.getTotal());
                    evalMap.put(hv.getName(), tt.getValue());
                }
                tt.reset();
            } else {
                for (int j = 0; j < fieldIndexs.length; j++) {
                    if (fieldIndexs[j] == i) {
                        if (oldValues == null)
                            label.setValue(oldValue[j] == null ? ""
                                    : oldValue[j].toString());
                        else
                            label.setValue(oldValues[j] == null ? ""
                                    : oldValues[j].toString());
                        break;
                    }
                }
                if (evalMap != null)
                    evalMap.put(hv.getName(), label.getValue());
            }
            if (evalMap != null)
                managedComponents.put(hv.getName(), label);
            if (!Strings.isBlank(hv.getGroupStyle()))
                label.setStyle(hv.getGroupStyle());
            row.appendChild(label);
        }
        if (groupEngine != null)
            groupEngine.exec(null, managedComponents, evalMap);
        return row;
    }

    private void createRow(ListRowVo rv, Map<String, Object> evalMap,
                           Map<String, Component> managedComponents) {
        Row row = new Row();
        if (!Strings.isBlank(rowStyle))
            row.setStyle(rowStyle);
        Object[] data = rv.getData();
        setIndex(true);// 往下累加
        int offset = 0;
        if (support.getEntity().isShowRowNumbers()) {
            offset++;
            Label label = new Label(String.valueOf(index));
            label.setParent(row);
        }
        CellCreater creater = SupportFactory.getCellCreater(support);
        for (int i = 0; i < data.length; i++) {
            ListHeaderVo hv = headers.get(i + offset);
            evalMap.put(hv.getName(), data[i]);
            if (hv.isTotal() && data[i] != null)
                hv.caculate(data[i].toString());
            Component c = creater.createCell(row, managedComponents, hv, rv, i);
//            if (c.getFirstChild() == null)
//                managedComponents.put(hv.getName(), c);
//            else
//                managedComponents.put(hv.getName(), c.getFirstChild());
            row.appendChild(c);
        }
        row.setValue(rv);
        row.setParent(rootNode);
        managedComponents.put("self", row);
        if (expressionEngine != null)
            expressionEngine.eval(row, evalMap, managedComponents);
    }

    @Override
    public void clear() {
        if (parent == null)
            rootNode.getChildren().clear();
        for (ListHeaderVo hv : headers) {
            if (hv.isTotal())
                hv.reset();
        }
        super.clear();
    }

    public int getMaxLevel() {
        return maxLevel;
    }

    @Override
    public void reset() {
        if (oldValue != null) {
            for (int i = 0; i < oldValue.length; i++)
                oldValue[i] = null;
        }
        if (child != null)
            child.reset();
    }

    @Override
    public void reIndex(boolean isDown) {
        index = 0;
        count = 0;
        if (isDown) {
            if (child != null)
                child.reIndex(isDown);
        } else if (parent != null)
            parent.reIndex(isDown);
    }

}
